
#include<vector>

#include <errno.h>
#include <sys/iomsg.h>
#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <string.h>

#include "Komunikacja.h"

using namespace std;

ConnectorAirport* ConnectorAirport::instance = NULL;

static sem_t mutexConns;

ConnectorAirport * ConnectorAirport::getInstance()
{
	if ( !instance ) {
		instance = new ConnectorAirport();
	}
	return instance;
}

ConnectorAirport::ConnectorAirport()
{
	connName = new char[CONN_NAME_LENGTH];
	connName[0] = 'a';
	for( int i = 0; i < CONN_NAME_LENGTH; i++)
		connName[i] = '\0';
	strcpy(connName, "NO_NAME");
	 
	 sem_init( &semAirportDB_AI, 0, 0);
	 sem_init( &semPlaneDB_AI, 0, 0);
	 
	 sem_init( &mutexConns, 0, 1);
	 
	 connectionsOpened = new std::vector<ConnFD>();
}

void ConnectorAirport::createListener( char * _connLocalName)
{

	/** zapisuje nazwe naszego kanalu**/

	strcpy(connName, _connLocalName);

	/** watek, ktory bedzie nasluchiwal**/
	pthread_attr_t attr;

   	pthread_attr_init( &attr );
   	pthread_attr_setdetachstate(
      		&attr, PTHREAD_CREATE_DETACHED );
      
	pthread_create( NULL, &attr, &run , _connLocalName );
}

void ConnectorAirport::setPtr( Komunikacja * kom)
{
	komAI = kom;
	 
}


 int  ConnectorAirport::isConnected( char * arg)
 {
 		int i;

 	for(i = 0; i < connectionsOpened->size() ; i++) {
			if(  strcmp(     (* connectionsOpened)[i].connName , arg)== 0) {
			//	cout << "takie same : "<< arg << " i : " <<(* connectionsOpened)[i].connName <<endl;
				return  (* connectionsOpened)[i].fd;
			}
	}
		
	return -1;
 }
 
ConnFD::ConnFD(  char * name, int _fd)
{
	fd=  _fd;
	connName = name;
}

void  ConnectorAirport::addConn( char * arg, int fd)
{
	char * par = new char[30];
	strcpy(par, arg);
	
	connectionsOpened->push_back( *(new ConnFD( par, fd)));		
}
 
 void  ConnectorAirport::closeAllConns( void )
{
	
	int i, j;
	vector <ConnFD>::iterator iter;
	
	sem_wait(&mutexConns);
	
	iter = connectionsOpened->begin();
	i = 	connectionsOpened->size();
	for( j = 0; j < i; j++) {
		name_close( (*iter).fd);
		connectionsOpened->erase(iter);
		iter = connectionsOpened->begin();
	}
//	cout << "closeAllConns . polaczen jest  : "<< 	connectionsOpened->size() << endl;
	
	sem_post(&mutexConns);
}



/*** Client Side of the code ***/
int sendMessage(  Message arg) {

    my_data_t * msg = &arg.data;
    int fd;
	
	 sem_wait(&mutexConns);
	 
	if( (fd = ConnectorAirport::getInstance()->isConnected(arg.getConnReceiverName()))==-1 ) {
    	if ((fd = name_open (arg.getConnReceiverName(), NAME_FLAG_ATTACH_GLOBAL)) == -1) {
    		cout <<"\nERROR sendMessage. pewnie nie ma " <<arg.getConnReceiverName() <<" albo gns -c zapomniales\n";
    	 	cout <<endl <<strerror(errno) << endl ;
    	 	sem_post(&mutexConns);
        	return EXIT_FAILURE;
    	}
    	ConnectorAirport::getInstance()->addConn(arg.getConnReceiverName(), fd);
    }

    /* We would have pre-defined data to stuff here */
    (*msg).hdr.type = 0x00;
    (*msg).hdr.subtype = 0x00;

     if (MsgSend(fd, &(*msg), sizeof(*msg), NULL, 0) == -1) {
  		cout <<"\nsendMessage ERROR1 destination\n";
    	cout <<endl <<strerror(errno) << endl ;
    	sem_post(&mutexConns);
        return EXIT_FAILURE;
    }
    
    if( (fd = ConnectorAirport::getInstance()->isConnected("GOOFY"))==-1 ) {
		if ((fd = name_open ( "GOOFY", NAME_FLAG_ATTACH_GLOBAL)) == -1) {
	  		cout <<"\nERROR sendMessage. pewnie nie ma goofy albo gns -c zapomniales\n";
	   		cout<< endl<<strerror(errno)<<endl;
	   		sem_post(&mutexConns);
        	return EXIT_FAILURE;
    	}
    	ConnectorAirport::getInstance()->addConn("GOOFY", fd);
   	}
   
    /* We would have pre-defined data to stuff here */
    (*msg).hdr.type = 0x00;
    (*msg).hdr.subtype = 0x00;

  
    if (MsgSend(fd, &(*msg), sizeof(*msg), NULL, 0) == -1) {
    	cout <<endl<<"sendMessage ERROR2"<<endl;
      	cout<< endl<<strerror(errno)<<endl;
      	sem_post(&mutexConns);
        return EXIT_FAILURE;
    }
	
	sem_post(&mutexConns);
    return EXIT_SUCCESS;
}




/**
	Funkcja zajmujaca sie komunikatem, ktory przyszedl przez siec
**/
void * messageReceived( void * arg)
{
	
	char * nazwa;
	std::string alfa1;	
		
	Message * msg = ( Message *)arg;

	switch( msg->getType()) {

		case FAILURE_EV_PO :
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_setAwaria( std::string(msg->getStringArg1()), std::string(msg->getStringArg2()),  msg->getIntArg1());
			break;
		
		case FAILURE_OVER_EV_PO :
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_resetAwaria( msg->getStringArg1());
			break;
		
		case RES_GET_AIRPORT_AI_DB :
			ConnectorAirport::getInstance()-> airportCameAI(msg);
			sem_post(&ConnectorAirport::getInstance()->semAirportDB_AI);
			break;
		
		case RES_GET_PLANE_AI_DB :
			ConnectorAirport::getInstance()-> planeCameAI(msg);
			sem_post(&ConnectorAirport::getInstance()->semPlaneDB_AI);
			break;	
			
		case MSG_ZGLOSZENIE_GOTOWOSCI_DO_STARTU :	
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_ChceStartowac(atoi(msg->getConnSenderName()));
			break;
			
		case  MSG_ZGLOSZENIE_GOTOWOSCI_DO_LADOWANIA :	
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_ChceLadowac(atoi(msg->getConnSenderName()), msg->getBoolArg1());
			break;
			
		case MSG_OPUSCILES_STREFE_WPLYWOW :	
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_samolotStrefaOUT( atoi(msg->getConnSenderName()), "wtf?");
			break;
		
		case MSG_AKTUALNA_POZYCJA :	
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_polozenieSamolotu(atoi(msg->getConnSenderName()), msg->getFloatArg1(), msg->getFloatArg2());
			break;
		
		case MSG_POJAWIAM_SIE_NA_LOTNISKU :
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_samolotNaLotnisku(atoi(msg->getConnSenderName()), msg->getStringArg1());
			break;
			
		case MSG_NOWA_MASZYNA_W_STREFIE :
			ConnectorAirport::getInstance()->getKomunikacja()->Kom_samolotStrefaIN(atoi(msg->getConnSenderName()), msg->getStringArg1());
			break;	
			
		/**
		
			
			break;
		**/
		
		default:	break;
		}
}


void messageHandler( Message  * msg)
{

	/* watek, ktory bedzie nasluchiwal*/
	pthread_attr_t attr;

   	pthread_attr_init( &attr );
   	pthread_attr_setdetachstate(
      		&attr, PTHREAD_CREATE_DETACHED );
      		
	pthread_create( NULL, &attr, &messageReceived, msg );
}



/**
	Funkcja obslugujaca nasluchiwanie na zadania z sieci
**/
void* run( void*  arg) {

   name_attach_t *attach;

   Message msg;
    Message * msgProper;
   int rcvid;
	
   /* Create a local name (/dev/name/local/...) */
   if ((attach = name_attach(NULL, (char *)  arg, NAME_FLAG_ATTACH_GLOBAL)) == NULL) {
   	cout << "ERROR,  run: #"<< strerror(errno) << endl;
    return (void*)EXIT_FAILURE;
   }

   /* Do your MsgReceive's here now with the chid */
   while (1) {

       rcvid = MsgReceive(attach->chid, &(msg.data), sizeof(msg.data), NULL);

		
       if (rcvid == -1) {/* Error condition, exit */
           break;
       }

       if (rcvid == 0) {/* Pulse received */
           switch (msg.data.hdr.code) {
           case _PULSE_CODE_DISCONNECT:
               /*
                * A client disconnected all its connections (called
                * name_close() for each name_open() of our name) or
                * terminated
                */
                ConnectorAirport::getInstance()->closeAllConns();
               ConnectDetach(msg.data.hdr.scoid);
               break;
           case _PULSE_CODE_UNBLOCK:
               /*
                * REPLY blocked client wants to unblock (was hit by
                * a signal or timed out).  It's up to you if you
                * reply now or later.
                */
               break;
           
           }
           continue;
       }


       /* name_open() sends a connect message, must EOK this */
       if (msg.data.hdr.type == _IO_CONNECT ) {
           MsgReply( rcvid, EOK, NULL, 0 );
           continue;
       }

       /* Some other QNX IO message was received; reject it */
       if (msg.data.hdr.type > _IO_BASE && msg.data.hdr.type <= _IO_MAX ) {
           MsgError( rcvid, ENOSYS );
           continue;
       }

       /* A message (presumable ours) received, handle */

     	MsgReply(rcvid, EOK, 0, 0);
     
  		msgProper = new Message();
		msg.copyMessage(msgProper);    
    
   // 	cout << "Po MsgReply"<<endl;
   
      messageHandler(msgProper);


   } 

   /* Remove the name from the space */
   name_detach(attach, 0);


   return (void*) 0;
}

void ConnectorAirport::setAirportAI( lotniskoEv * arg)
{
	airportAI = arg;	
}

	
void ConnectorAirport::airportCameAI( Message * msg)
{
	char * nazwa = new char[CONN_NAME_LENGTH];
	strcpy( nazwa, msg->getStringArg1() );	

	airportAI->nazwa = std::string(nazwa);
	airportAI->id_lotniska = msg->getIntArg4();
	airportAI->pojemnosc =  msg->getIntArg1();
	airportAI->szerokosc_geo = msg->getFloatArg1();	
	airportAI->dlugosc_geo = msg->getFloatArg2();
	airportAI->ilosc_szerokich_pasow =  msg->getIntArg2();
	airportAI->ilosc_waskich_pasow = msg->getIntArg3();

}


void ConnectorAirport::setPlaneAI( samolot_dla_lotniska * arg)
{
	planeAI = arg;	
}

	
void ConnectorAirport::planeCameAI( Message * msg)
{
	planeAI->czas_obslugi = msg->getIntArg1();
	planeAI->czy_szeroki =  msg->getBoolArg1();

}

char * ConnectorAirport::getConnName( void)
{
	return connName;
}

Komunikacja * ConnectorAirport::getKomunikacja( void)
{
	return komAI;
}


